package MultithreadCase;


/*import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

//标准库里的 阻塞队列
//BlockingQueue 也有 offer, poll, peek 等方法, 但是这些方法不带有阻塞特性
BlockingQueue 是一个接口. 真正实现的类是 LinkedBlockingQueue

public class BlockingQueueTest {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>();
        queue.put("hello");
        // 出队列. 如果没有 put 直接 take, 就会阻塞
        System.out.println(queue.take());
    }
}*/


/*import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
//基于这个内置的阻塞队列实现 生产者消费者模型
public class BlockingQueueTest{
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();

        Thread producer = new Thread(() -> {
            int num = 0;
            while (true){
                System.out.println("生产了" + num);
                try {
                    queue.put(num);
                    num++;
                    Thread.sleep(500);//当生产的慢一些话，消费者就会与生产者同步，生产多少消费多少
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread customer = new Thread(() -> {
           while (true){
               try {
                   int ret = queue.take();
                   System.out.println("消费了" + ret);
                   //Thread.sleep(500);  当消费的慢一些话，就是生产的很快，消费不过来
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }

           }
        });

        producer.start();
        customer.start();
    }
}*/



//基于 数组 实现一个阻塞队列
//1.先实现一个循环队列:基于数组来，实现入队列和出队列操作。注意判断队列为空和为满的情况、
//2.给队列加上线程安全:直接给put和take方法加锁就可以保证线程安全
//3.给队列加上阻塞：使用wait和notify机制。对于put，阻塞条件为队列为满；对于take，阻塞条件为空。

class MyBlockingQueue{
    private int[] data = new int[1000];
    //数组有效个数
    private int size = 0;
    //队首下标
    private int head = 0;
    //队尾下标
    private int tail = 0;

    //入队列
    synchronized public void put(int value) throws InterruptedException {
        if (size == data.length){
            //队列满了，暂时先直接返回
            //return;
            this.wait();//put中的wait要由take来唤醒：只要take成功，队列就不为满
        }
        //把新的元素放到tail位置
        data[tail] = value;
        tail++;
        //处理tail到达末尾的情况
        //tail = tail % data.length; 不建议使用
        if (tail >= data.length){
            tail = 0;//从头开始
        }
        size++;
        this.notify();//put成功后就唤醒 take中的wait
    }

    //出队列
    synchronized public Integer take() throws InterruptedException {
        if (size == 0){
            //如果队列为空，就返回一个非法值
            //return null;
            this.wait();//take 中的等待要由 put来唤醒：当put成功后，队列就不为空。
        }
        //取出head位置的元素
        int ret = data[head];
        head++;
        if (head >= data.length){
            return 0;
        }
        size--;
        //take成功后就唤醒put中的wait
        this.notify();
        return ret;
    }

}
public class BlockingQueueTest{
    //用自己实现的阻塞队列MyBlockingQueue来完成 生产者消费者模型
    private static MyBlockingQueue queue = new MyBlockingQueue();

    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            int num = 0;
            while (true){
                System.out.println("生产了" + num);
                try {
                    queue.put(num);
                    num++;
                    //Thread.sleep(500);//当生产的慢一些话，消费者就会与生产者同步，生产多少消费多少
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread customer = new Thread(() -> {
            while (true){
                try {
                    int ret = queue.take();
                    System.out.println("消费了" + ret);
                    Thread.sleep(500);  //当消费的慢一些话，就是生产的很快，后面消费一个才会生产一个，也有可能消费两个生产两个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });

        producer.start();
        customer.start();
    }

}

